/*
 * Copyright 2022-2023 the original author(https://github.com/wj596)
 * 
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * </p>
 */
package org.jsets.fastboot.flowable.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.GraphicInfo;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.jsets.fastboot.flowable.config.FlowableConfig;
import org.jsets.fastboot.flowable.mapper.TaskTraceMapper;
import org.jsets.fastboot.flowable.model.dto.NodeTrace;
import org.jsets.fastboot.flowable.model.entity.TaskTrace;
import org.jsets.fastboot.flowable.service.ITaskTraceService;
import org.jsets.fastboot.persistent.support.LambdaQuerier;
import org.jsets.fastboot.util.CollectionUtils;
import org.jsets.fastboot.util.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;

/**
 * 流程追踪服务实现
 * @author wangjie (https://github.com/wj596)
 * @date 2021.06.25 11:23
 */
@Slf4j
@Service
public class TaskTraceService extends ServiceImpl<TaskTraceMapper,TaskTrace> implements ITaskTraceService {

	@Autowired
	private FlowEngineService flowEngine;
	
	@Override
	public List<TaskTrace> selectByInstance(String instanceId) {
		return new LambdaQuerier<TaskTrace>()
				.setBaseMapper(this.getBaseMapper())
				.eq(TaskTrace::getInstanceId, instanceId)
				.orderByAsc(TaskTrace::getCompleteTime)
				.selectList();
	}

	@Override
	public List<NodeTrace> selectNodeTraceByInstance(String processInstanceId) {
		String processDefinitionId = "";
		ProcessInstance processInstance = this.flowEngine.getRuntimeService().createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
		if (processInstance==null) {
			HistoricProcessInstance historicProcessInstance = this.flowEngine.getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
			processDefinitionId = historicProcessInstance.getProcessDefinitionId();
		}else {
			processDefinitionId = processInstance.getProcessDefinitionId();
		}
		BpmnModel bpmnModel = this.flowEngine.getRepositoryService().getBpmnModel(processDefinitionId);
		Map<String, TaskTrace> taskTraces = Maps.newHashMap();
		this.selectByInstance(processInstanceId).forEach(t->{
			taskTraces.put(t.getTaskId(), t);
		});
		
		List<NodeTrace> nodeTraces = new ArrayList<>();
		List<HistoricActivityInstance> historicActivities = this.flowEngine.getHistoryService().createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().orderByHistoricActivityInstanceEndTime().asc().list();
		for (HistoricActivityInstance tempActivity : historicActivities) {
			String activityType = tempActivity.getActivityType();
			if (FlowableConfig.ACTIVITY_TYPE_SEQUENCE_FLOW.equals(activityType)) {
				continue;
			}
			if (FlowableConfig.ACTIVITY_TYPE_EXCLUSIVE_GATEWAY.equals(activityType)) {
				continue;
			}
			String activityId = tempActivity.getActivityId();
			NodeTrace nodeTrace = new NodeTrace();
			nodeTrace.setAtivityId(activityId);
			nodeTrace.setAtivityType(tempActivity.getActivityType());
			nodeTrace.setAtivityName(tempActivity.getActivityName());
			nodeTrace.setSubmitTime(tempActivity.getStartTime());
			nodeTrace.setEndTime(tempActivity.getEndTime());
			nodeTrace.setCompleted(null != tempActivity.getEndTime());
			GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(tempActivity.getActivityId());
			nodeTrace.setX(graphicInfo.getX());
			nodeTrace.setY(graphicInfo.getY());
			nodeTrace.setWidth(graphicInfo.getWidth());
			nodeTrace.setHeight(graphicInfo.getHeight());
			TaskTrace taskTrace = taskTraces.get(tempActivity.getTaskId());
			if (null != taskTrace) {
				nodeTrace.setTaskId(taskTrace.getTaskId());
				nodeTrace.setBusinessKey(taskTrace.getBusinessKey());
				nodeTrace.setBusinessType(taskTrace.getBusinessType());
				nodeTrace.setUsername(taskTrace.getUsername());
				nodeTrace.setComment(taskTrace.getComment());
				nodeTrace.setResult(taskTrace.getResult());
				nodeTrace.setCompleteTime(taskTrace.getCompleteTime());
			}
			nodeTraces.add(nodeTrace);
		}
		return nodeTraces;
	}
	
}